作者:Demoer | 来源:互联网 | 2023-05-28 15:12
根据我的理解,这两种方法都适用于生成器中的每个项目:
让我们i
成为运营商的目标
让my_iter
我们的发电机
让可驯服的do_something_with
回报None
而Loop + StopIteratioon
try:
while True:
i = next(my_iter)
do_something_with(i)
except StopIteration:
pass
对于循环/列表理解
for i in my_iter:
do_something_with(i)
[do_something_with(i) for i in my_iter]
次要编辑:print(i)
用do_something_with(i)
@kojiro建议替换,以便用解释器机制消除用例的歧义.
据我所知,这些都是迭代生成器的适用方法,有没有理由偏爱另一个?
现在for循环看起来比我优越.由于:较少的线条/杂乱和一般的可读性,加上单个缩进.
我真的只看到while方法是有利的,如果你想在特定异常上轻松打破循环.
1> SingleNegati..:
第三个选择是明确不一样的第2位.第三个例子创建了一个列表,每个列表都有一个返回值print(i)
,它恰好是None
,所以不是一个非常有趣的列表.
前两个在语义上相似.存在轻微的技术差异; 如所示,while循环不起作用my_iter
,实际上是迭代器(即,有一个__next__()
方法); 例如,如果是的话list
.__iter__()
除了迭代器之外,for循环适用于所有迭代(有一个方法).
因此,正确的版本是:
my_iter = iter(my_iterable)
try:
while True:
i = next(my_iter)
print(i)
except StopIteration:
pass
现在,除了可读性原因之外,实际上有一个技术原因你应该更喜欢for循环; 对于在紧密内部循环中执行的字节码数量,你需要支付一个惩罚(在CPython中,无论如何).让我们比较:
In [1]: def forloop(my_iter):
...: for i in my_iter:
...: print(i)
...:
In [57]: dis.dis(forloop)
2 0 SETUP_LOOP 24 (to 27)
3 LOAD_FAST 0 (my_iter)
6 GET_ITER
>> 7 FOR_ITER 16 (to 26)
10 STORE_FAST 1 (i)
3 13 LOAD_GLOBAL 0 (print)
16 LOAD_FAST 1 (i)
19 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
22 POP_TOP
23 JUMP_ABSOLUTE 7
>> 26 POP_BLOCK
>> 27 LOAD_CONST 0 (None)
30 RETURN_VALUE
内循环vs中调用的7个字节码:
In [55]: def whileloop(my_iterable):
....: my_iter = iter(my_iterable)
....: try:
....: while True:
....: i = next(my_iter)
....: print(i)
....: except StopIteration:
....: pass
....:
In [56]: dis.dis(whileloop)
2 0 LOAD_GLOBAL 0 (iter)
3 LOAD_FAST 0 (my_iterable)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 STORE_FAST 1 (my_iter)
3 12 SETUP_EXCEPT 32 (to 47)
4 15 SETUP_LOOP 25 (to 43)
5 >> 18 LOAD_GLOBAL 1 (next)
21 LOAD_FAST 1 (my_iter)
24 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
27 STORE_FAST 2 (i)
6 30 LOAD_GLOBAL 2 (print)
33 LOAD_FAST 2 (i)
36 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
39 POP_TOP
40 JUMP_ABSOLUTE 18
>> 43 POP_BLOCK
44 JUMP_FORWARD 18 (to 65)
7 >> 47 DUP_TOP
48 LOAD_GLOBAL 3 (StopIteration)
51 COMPARE_OP 10 (exception match)
54 POP_JUMP_IF_FALSE 64
57 POP_TOP
58 POP_TOP
59 POP_TOP
8 60 POP_EXCEPT
61 JUMP_FORWARD 1 (to 65)
>> 64 END_FINALLY
>> 65 LOAD_CONST 0 (None)
68 RETURN_VALUE
内循环中的9个字节码.
不过,我们实际上可以做得更好.
In [58]: from collections import deque
In [59]: def deqloop(my_iter):
....: deque(map(print, my_iter), 0)
....:
In [61]: dis.dis(deqloop)
2 0 LOAD_GLOBAL 0 (deque)
3 LOAD_GLOBAL 1 (map)
6 LOAD_GLOBAL 2 (print)
9 LOAD_FAST 0 (my_iter)
12 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
15 LOAD_CONST 1 (0)
18 CALL_FUNCTION 2 (2 positional, 0 keyword pair)
21 POP_TOP
22 LOAD_CONST 0 (None)
25 RETURN_VALUE
一切都发生在C, collections.deque
,map
并且print
都内建命令.(对于cpython)所以在这种情况下,没有执行循环的字节码.当迭代步骤是ac函数时,这只是一个有用的优化(就像这样print
.否则,python函数调用的JUMP_ABSOLUTE
开销大于开销.